﻿// ***********************************************************************
// Assembly         : INNOVACALL.Framework.Common
// Author           : LJO+01 (Laurent Jordi)
// Created          : 06-06-2013
// Last Modified By : LJO+01 (Laurent Jordi)
// Last Modified On : 06-06-2013
// ***********************************************************************
// <copyright file="XMLFactory.cs" company="Copyright © Innovacall 2011">
//     Copyright (c) Copyright © Innovacall 2011. All rights reserved.
// </copyright>
// <summary></summary>
// ***********************************************************************
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;

namespace INNOVACALL.Framework.Common.XMLTools
{
    /// <summary>
    /// Class XMLFactory
    /// </summary>
    public class XMLFactory
    {

        /// <summary>
        /// Gets or sets the current document.
        /// </summary>
        /// <value>The current document.</value>
        public XDocument CurrentDocument { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="XMLFactory"/> class.
        /// </summary>
        public XMLFactory() { }

        /// <summary>
        /// Initializes a new instance of the <see cref="XMLFactory"/> class.
        /// </summary>
        /// <param name="xmlDocumentString">The XML document string.</param>
        public XMLFactory(string xmlDocumentString)
        {
            this.CurrentDocument = XDocument.Load(new StringReader(xmlDocumentString));
        }


        #region Properties
        /// <summary>
        /// Enum ACTION
        /// </summary>
        public enum ACTION { COPY = 1, MOVE };
        /// <summary>
        /// Enum POSITION
        /// </summary>
        public enum POSITION { BEFORE = 1, AFTER, FIRST, LAST };
        #endregion

        #region Public Methods

        /// <summary>
        /// Saves to string.
        /// </summary>
        /// <returns>System.String.</returns>
        public string SaveToString()
        {
            string toReturn = string.Empty;
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.Encoding = new UTF8Encoding();
            using (var stream = new MemoryStream())
            {
                using (XmlWriter writer = XmlWriter.Create(stream, xmlWriterSettings))
                {
                    this.CurrentDocument.Save(writer);
                }
                toReturn = Encoding.UTF8.GetString(stream.ToArray());
            }
            return toReturn;
        }

        /// <summary>
        /// Déplace ou copie le noeud sélectionné vers un emplacement sélectionné
        /// </summary>
        /// <param name="xDocumentSource">The x document source.</param>
        /// <param name="xPathSource">The x path source.</param>
        /// <param name="xDocumentCible">The x document cible.</param>
        /// <param name="xPathCible">The x path cible.</param>
        /// <param name="action">Copie ou Déplace</param>
        /// <exception cref="System.Exception">
        /// Action incorrecte
        /// or
        /// XPath incorrecte
        /// </exception>
        public void MoveNode(XDocument xDocumentSource, String xPathSource, XDocument xDocumentCible, String xPathCible, int action)
        {
            XElement xElementSource = xDocumentSource.XPathSelectElement(xPathSource);
            XElement xElementCible = xDocumentCible.XPathSelectElement(xPathCible);
            if (xElementSource != null && xElementCible != null)
            {
                switch (action)
                {
                    case 1:
                        xElementCible.AddAfterSelf(xElementSource);
                        break;
                    case 2:
                        xElementCible.AddAfterSelf(xElementSource);
                        xElementSource.Remove();
                        break;
                    default:
                        throw new Exception("Action incorrecte");
                }
            }
            else
            {
                throw new Exception("XPath incorrecte");
            }
        }

        /// <summary>
        /// Supprime le noeud sélectionné
        /// </summary>
        /// <param name="xDocumentSource">The x document source.</param>
        /// <param name="xPathSource">The x path source.</param>
        /// <param name="RecurseChildren">Si false, alors le noeud sélectionné ne doit pas avoir d'enfants pour être supprimé</param>
        /// <exception cref="System.Exception">Ce noeud possède des enfants</exception>
        public void RemoveNode(XDocument xDocumentSource, String xPathSource, bool RecurseChildren)
        {
            XElement xElementSource = xDocumentSource.XPathSelectElement(xPathSource);
            if (xElementSource != null)
            {
                if (xElementSource.HasElements && !RecurseChildren)
                {
                    throw new Exception("Ce noeud possède des enfants");
                }
                xElementSource.Remove();
            }
        }

        /// <summary>
        /// Remplace le noeud sélectionné par xElement
        /// </summary>
        /// <param name="xElement">The x element.</param>
        /// <param name="xDocumentCible">The x document cible.</param>
        /// <param name="xPathCible">The x path cible.</param>
        /// <exception cref="System.Exception">XPath incorrecte</exception>
        public void ReplaceNode(XElement xElement, XDocument xDocumentCible, String xPathCible)
        {
            XElement xElementCible = xDocumentCible.XPathSelectElement(xPathCible);
            if (xElementCible != null)
            {
                xElementCible.Parent.AddFirst(xElement);
                xElementCible.Remove();
            }
            else
            {
                throw new Exception("XPath incorrecte");
            }
        }

        /// <summary>
        /// Insère xElement à l'emplacement sélectionné
        /// </summary>
        /// <param name="xElement">The x element.</param>
        /// <param name="xDocumentCible">The x document cible.</param>
        /// <param name="xPathCible">The x path cible.</param>
        /// <param name="Position">AFTER - BEFORE - FIRSTCHILD - LASTCHILD</param>
        /// <exception cref="System.Exception">
        /// Position invalide
        /// or
        /// XPath incorrecte
        /// </exception>
        public void InsertNode(XElement xElement, XDocument xDocumentCible, String xPathCible, int Position)
        {
            XElement xElementCible = xDocumentCible.XPathSelectElement(xPathCible);
            if (xElementCible != null)
            {
                switch (Position)
                {
                    case 1:
                        xElementCible.AddAfterSelf(xElement);
                        break;
                    case 2:
                        xElementCible.AddBeforeSelf(xElement);
                        break;
                    case 3:
                        xElementCible.AddFirst(xElement);
                        break;
                    case 4:
                        xElementCible.Add(xElement);
                        break;
                    default:
                        throw new Exception("Position invalide");
                }
            }
            else
            {
                throw new Exception("XPath incorrecte");
            }
        }

        /// <summary>
        /// Ajoute l'attribut xAttribute à xElement
        /// </summary>
        /// <param name="xElement">The x element.</param>
        /// <param name="xAttribute">The x attribute.</param>
        public void AddAttribute(XElement xElement, XAttribute xAttribute)
        {
            xElement.Add(xAttribute);
        }

        /// <summary>
        /// Supprime l'attribut xAttribute de xElement
        /// </summary>
        /// <param name="xElement">The x element.</param>
        /// <param name="xAttribute">The x attribute.</param>
        public void RemoveAttribute(XElement xElement, XAttribute xAttribute)
        {
            xElement.Attributes(xAttribute.Name).Remove();
        }

        /// <summary>
        /// Définit la valeur de l'attribut xAttribute
        /// </summary>
        /// <param name="xAttribute">The x attribute.</param>
        /// <param name="value">The value.</param>
        public void SetAttributeValue(XAttribute xAttribute, string value)
        {
            xAttribute.SetValue(value);
        }

        /// <summary>
        /// Efface la valeur de l'attribut xAttribute
        /// </summary>
        /// <param name="xAttribute">The x attribute.</param>
        public void ClearAttributeValue(XAttribute xAttribute)
        {
            xAttribute.SetValue(null);
        }

        /// <summary>
        /// Efface la valeur du noeud xElement
        /// </summary>
        /// <param name="xElement">The x element.</param>
        public void ClearNodeContent(XElement xElement)
        {
            xElement.SetValue(null);
        }

        /// <summary>
        /// Définit la valeur du noeud xElement
        /// </summary>
        /// <param name="xElement">The x element.</param>
        /// <param name="value">The value.</param>
        public void SetNodeContent(XElement xElement, string value)
        {
            xElement.SetValue(value);
        }

        /// <summary>
        /// Remplace toutes les occurences d'une valeur par une autre valeur
        /// </summary>
        /// <param name="xElement">The x element.</param>
        /// <param name="valueToBeReplaced">The value to be replaced.</param>
        /// <param name="valueWhichReplace">The value which replace.</param>
        public void ReplaceInContent(XElement xElement, string valueToBeReplaced, string valueWhichReplace)
        {
            xElement.SetValue(xElement.Value.Replace(valueToBeReplaced, valueWhichReplace));
        }
        #endregion
    }
}
